home *** CD-ROM | disk | FTP | other *** search
/ NeXT Enterprise Objects Framework 1.1 / NeXT Enterprise Objects Framework 1.1.iso / NextDeveloper / Examples / EnterpriseObjects / SHLExamples / Sorting / SlidingMatrix.m < prev    next >
Encoding:
Text File  |  1994-07-31  |  8.1 KB  |  314 lines

  1. /*--------------------------------------------------------------------------
  2.  *
  3.  *     You may freely copy, distribute, and reuse the code in this example.
  4.  *     SHL Systemhouse disclaims any warranty of any kind, expressed or  
  5.  *    implied, as to its fitness for any particular use.
  6.  *
  7.  *
  8.  *    SlidingMatrix
  9.  *
  10.  *    Inherits From:        Matrix
  11.  *
  12.  *    Conforms To:        None.
  13.  *
  14.  *    Declared In:        SlidingMatrix.h
  15.  *
  16.  *
  17.  *------------------------------------------------------------------------*/
  18. #import "SlidingMatrix.h"
  19.  
  20.  
  21. static int            rowDropped;
  22. static int            rowDragged;
  23. static BOOL            isDragging;
  24. static NXPoint        currentMouse;
  25.  
  26.  
  27. #define BOUND(__a,__low,__high) MIN(MAX((__a),(__low)),(__high))
  28.  
  29.  
  30.  
  31.  
  32. @implementation SlidingMatrix
  33.  
  34. /*--------------------------------------------------------------------------
  35.  *    Private Methods
  36.  *------------------------------------------------------------------------*/
  37. - _exchangeRowAt: (int) source with: (int) destination
  38. {
  39.     int    iterator;
  40.     id    sourceCell, destinationCell;
  41.     
  42.     for (iterator = 0; iterator < numCols; iterator++)
  43.         {
  44.         sourceCell = [self cellAt: source : iterator];
  45.         destinationCell = [self cellAt: destination : iterator];
  46.         [self putCell: sourceCell  at: destination : iterator];
  47.         [self putCell: destinationCell  at: source : iterator];
  48.         }
  49.         
  50.     return self;
  51. }
  52.  
  53.  
  54. - _reflectScroll
  55. {
  56.     //  If in a ScrollView, reflect scroll if drag is beyond visibleRect...
  57.     
  58.     id            scrollView = [superview superview];
  59.     id            clipView  = superview;
  60.     NXRect        visibleRect, clipViewBoundsRect;
  61.     NXCoord        delta;
  62.  
  63.     [self getVisibleRect: &visibleRect];
  64.     delta = (currentMouse.y + cellSize.height) - (NX_HEIGHT (&visibleRect) + NX_Y 
  65.         (&visibleRect));
  66.  
  67.     if (delta > 0.0)
  68.         {
  69.         [clipView getBounds: &clipViewBoundsRect];
  70.         NX_Y (&clipViewBoundsRect) += delta;
  71.         [clipView rawScroll: &clipViewBoundsRect.origin];
  72.         [scrollView reflectScroll: clipView];
  73.         }
  74.     else
  75.         {
  76.         delta = NX_Y (&visibleRect) - currentMouse.y;
  77.         if (delta > 0.0)
  78.             {
  79.             [clipView getBounds: &clipViewBoundsRect];
  80.             NX_Y (&clipViewBoundsRect) -= delta;
  81.             [clipView rawScroll: &clipViewBoundsRect.origin];
  82.             [scrollView reflectScroll: clipView];
  83.             }
  84.         }
  85.  
  86.     return self;
  87. }
  88.  
  89.  
  90. - _reflectSlide
  91. {
  92.     //  Here's where we actually adjust the cells to reflect the slide.  Insert
  93.     //  a new cell at the drop row (this moves any rows > than drop row by
  94.     //  one).  Exchange the dragged cell with the newly inserted cell.  Remove
  95.     //  the original dragged row. If user has dragged beyond last cell, add to
  96.     //  end.
  97.         
  98.     int        rowDraggedOffset = 0;
  99.     NXRect    rect;
  100.     NXPoint    mouseLocation;
  101.  
  102.     [window getMouseLocation: &mouseLocation];
  103.     [self getBounds: &rect];
  104.     [self convertRect: &rect  toView: nil];
  105.     if (rowDropped == numRows -1  &&  mouseLocation.y < NX_Y (&rect))
  106.           rowDropped++;
  107.  
  108.     [window disableFlushWindow];
  109.  
  110.     [self insertRowAt: rowDropped];
  111.     if (rowDropped < rowDragged)  {  rowDragged++;  rowDraggedOffset = 1;  }
  112.     selectedRow = rowDropped;
  113.     [self _exchangeRowAt: rowDragged  with: rowDropped];
  114.     [self removeRowAt: rowDragged  andFree: YES];
  115.  
  116.     rowDragged -= rowDraggedOffset;
  117.  
  118.     [self display];
  119.     [window reenableFlushWindow];
  120.     [window flushWindow];
  121.     return self;
  122. }
  123.  
  124.  
  125. - (BOOL) _notifyDelegateWillSlideFromRow: (int) sourceRow
  126. {
  127.     if (delegate  && [delegate respondsTo:
  128.             @selector (slidingMatrix:willSlideFromRow:)])
  129.         return [delegate slidingMatrix: self  willSlideFromRow: sourceRow ];
  130.         
  131.     return YES;
  132. }
  133.  
  134.  
  135. - (BOOL) _notifyDelegateWillSlideToRow: (int) destinationRow
  136. {
  137.     if (delegate  &&  [delegate respondsTo:
  138.             @selector (slidingMatrix:willSlideToRow:)])
  139.         return [delegate slidingMatrix: self  willSlideToRow: destinationRow];
  140.         
  141.     return YES;
  142. }
  143.  
  144.  
  145. - _notifyDelegateDidSlideFromRow: (int) sourceRow  toRow: (int) destinationRow
  146. {
  147.     if (delegate  &&  [delegate respondsTo:
  148.             @selector (slidingMatrix:didSlideFromRow:toRow:)])
  149.         [delegate slidingMatrix:self didSlideFromRow:sourceRow 
  150.                 toRow:destinationRow];
  151.         
  152.     return self;
  153. }
  154.  
  155.  
  156. /*--------------------------------------------------------------------------
  157.  *    Initialization and Freeing
  158.  *------------------------------------------------------------------------*/
  159. - initFrame: (const NXRect*) frameRect
  160. {
  161.     id buttonCellPrototype = [[ButtonCell allocFromZone: [self zone]]
  162.             initTextCell:"empty"];
  163.     [buttonCellPrototype setIconPosition:NX_ICONLEFT];
  164.     [buttonCellPrototype setBordered:NO];
  165.     [buttonCellPrototype setIcon:"empty"];
  166.     [buttonCellPrototype setAlignment:NX_LEFTALIGNED];
  167.     [buttonCellPrototype setType:NX_ONOFF];
  168.  
  169.     [super initFrame:(const NXRect *)frameRect mode:NX_RADIOMODE
  170.         prototype:buttonCellPrototype numRows:0 numCols:0];
  171.  
  172.     return self;
  173. }
  174.  
  175.  
  176. /*--------------------------------------------------------------------------
  177.  *    Accessing the deleagate
  178.  *------------------------------------------------------------------------*/
  179. - delegate
  180. {
  181.     return delegate;
  182. }
  183.  
  184.  
  185. - setDelegate: anObject
  186. {
  187.     delegate = anObject;
  188.     return self;
  189. }
  190.  
  191.  
  192. /*--------------------------------------------------------------------------
  193.  *    Event Handling
  194.  *------------------------------------------------------------------------*/
  195. - mouseDown: (NXEvent*) theEvent
  196. {
  197.     int             column, originalEventMask;
  198.     BOOL        scrollViewFlag;
  199.     NXRect         cellFrame, visibleRect;
  200.     NXCoord     offset;
  201.     NXEvent*     nextEvent;
  202.  
  203.     //  Is user control-dragging...
  204.     if ( ! (theEvent->flags & NX_CONTROLMASK))
  205.         return [super mouseDown: theEvent];
  206.  
  207.     //  Is there a valid row under the mouse...
  208.     currentMouse = theEvent->location;
  209.     [self convertPoint: ¤tMouse fromView: nil];
  210.     [self getRow: &rowDragged  andCol: &column  forPoint: ¤tMouse];
  211.     if (rowDragged == -1)  return [super mouseDown: theEvent];
  212.     if ([self _notifyDelegateWillSlideFromRow: rowDragged] == NO)
  213.         return [super mouseDown: theEvent];
  214.     [self selectCellAt: rowDragged : column];
  215.  
  216.     //  Calculate offset (difference between mouse hit y coord and
  217.     //    cellFrame y coord).  
  218.     [self getCellFrame: &cellFrame at: rowDragged : column];
  219.     offset = currentMouse.y - NX_Y (&cellFrame);
  220.  
  221.     //  Adjust currentMouse.y to cell frame boundary.
  222.     currentMouse.y -= offset;
  223.  
  224.     //  Prepare for event loop...
  225.     [window makeFirstResponder: window];
  226.     originalEventMask = [window addToEventMask: NX_MOUSEDRAGGEDMASK];
  227.     scrollViewFlag = ([[superview superview] isKindOf:
  228.             [ScrollView class]] ? YES : NO);
  229.     isDragging = YES;
  230.  
  231.     while (isDragging)
  232.         {
  233.         nextEvent = [NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK];
  234.         
  235.         switch (nextEvent->type)
  236.             {
  237.             case NX_MOUSEDRAGGED:
  238.                 isDragging = YES;
  239.                 currentMouse = nextEvent->location;
  240.                 [self convertPoint: ¤tMouse  fromView: nil];
  241.                 currentMouse.y -= offset;
  242.                 currentMouse.y = BOUND (currentMouse.y, NX_Y (&bounds),
  243.                     (NX_Y (&bounds) + NX_HEIGHT (&bounds) - cellSize.height));
  244.                 if  ([self getVisibleRect: &visibleRect]  &&  scrollViewFlag)
  245.                     [self _reflectScroll];
  246.                 [self displayFromOpaqueAncestor: &visibleRect  :1  :YES];
  247.                 break;
  248.  
  249.             case NX_MOUSEUP:
  250.                 isDragging = NO;
  251.                 currentMouse.y += cellSize.height / 2.0;
  252.  
  253.                 if ( ! [self getRow:&rowDropped andCol:&column
  254.                         forPoint:¤tMouse])
  255.                     {
  256.                     currentMouse.y += cellSize.height  / 4.0;
  257.                     if ( ! [self getRow:&rowDropped andCol:&column
  258.                         forPoint:¤tMouse])
  259.                         break;
  260.                     }
  261.     
  262.                 if ([self _notifyDelegateWillSlideToRow: rowDropped])
  263.                     {
  264.                     [self _reflectSlide];
  265.                     [self selectCellAt: rowDropped : column];
  266.                     [self _notifyDelegateDidSlideFromRow:rowDragged 
  267.                         toRow:rowDropped];
  268.                     }
  269.     
  270.                 break;
  271.             }
  272.         }  
  273.     
  274.     [self display];
  275.     [window setEventMask: originalEventMask];
  276.     return self;
  277. }
  278.  
  279.  
  280. /*--------------------------------------------------------------------------
  281.  *    Drawing Methods
  282.  *------------------------------------------------------------------------*/
  283. - drawSelf: (const NXRect*)rects : (int) rectCount
  284. {
  285.     int         iterator;
  286.     NXRect    rect;
  287.  
  288.     if (! isDragging)  return [super drawSelf: rects  : rectCount];
  289.  
  290.     [super drawSelf: rects  : rectCount];
  291.  
  292.     PSgsave ();
  293.     PSsetgray ([window backgroundGray]);
  294.     for (iterator = 0;  iterator < numCols; iterator++) 
  295.         {
  296.         [self getCellFrame: &rect  at: rowDragged : iterator];
  297.         NXRectFill (&rect);
  298.         }
  299.     PSgrestore();
  300.  
  301.  
  302.     for (iterator = 0;  iterator < numCols; iterator++) 
  303.         {
  304.         [self getCellFrame: &rect  at: rowDragged  : iterator];
  305.         NX_Y (&rect) = currentMouse.y;
  306.         [[self cellAt: rowDragged : iterator]  drawSelf: &rect  inView: self];
  307.         }
  308.         
  309.     return self;
  310. }
  311.  
  312.  
  313. @end
  314.